using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Attributes;

namespace Microsoft.WowAddonStudio.FrameXml.Components.Editors
{
	public class ControlSelectorEditor : UITypeEditor, IDisposable
	{
		private ControlSelectorUI selector;

		/// <summary>
		/// Gets the editor style used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"/> method.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that can be used to gain additional context information.</param>
		/// <returns>
		/// A <see cref="T:System.Drawing.Design.UITypeEditorEditStyle"/> value that indicates the style of editor used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"/> method. If the <see cref="T:System.Drawing.Design.UITypeEditor"/> does not support this method, then <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"/> will return <see cref="F:System.Drawing.Design.UITypeEditorEditStyle.None"/>.
		/// </returns>
		public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
		{
			return UITypeEditorEditStyle.DropDown;
		}


		/// <summary>
		/// Edits the specified object's value using the editor style indicated by the <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"/> method.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that can be used to gain additional context information.</param>
		/// <param name="provider">An <see cref="T:System.IServiceProvider"/> that this editor can use to obtain services.</param>
		/// <param name="value">The object to edit.</param>
		/// <returns>
		/// The new value of the object. If the value of the object has not changed, this should return the same object it was passed.
		/// </returns>
		public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
		{
			if (provider != null)
			{
				var editorService = (IWindowsFormsEditorService) provider.GetService(typeof (IWindowsFormsEditorService));
				var selectionService = (ISelectionService) provider.GetService(typeof (ISelectionService));
				var controlInstance = new List<Control>();

				if (selectionService != null)
				{
					controlInstance.AddRange(selectionService.GetSelectedComponents().OfType<Control>().ToArray());
				}

				var propertyDescriptor = context.PropertyDescriptor;
				var controlSelectorAttribute = propertyDescriptor.Attributes.OfType<ControlSelectorAttribute>().SingleOrDefault();
				var showAll = controlSelectorAttribute != null ? controlSelectorAttribute.ShowAll : false;

				if (selector == null)
				{
					selector = new ControlSelectorUI(provider, showAll, controlInstance);
				}

				editorService.DropDownControl(selector);

				return selector.Value;
			}

			return base.EditValue(context, provider, value);
		}

		#region IDisposable Members

		/// <summary>
		/// Performs application-defined tasks associated with freeing,
		/// releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Releases unmanaged and - optionally - managed resources
		/// </summary>
		/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
		protected virtual void Dispose(bool disposing)
		{
			if (selector != null) selector.Dispose();
		}

		#endregion
	}
}